<?php

declare(strict_types=1);

namespace app\service\user;

use app\model\User;
use app\model\UserAuth;
use app\model\UserIdentity;
use app\model\UserProfile;
use app\service\dto\ResultInterface;
use app\util\HashUtil;
use InvalidArgumentException;
use think\facade\Db;

class RegisterService
{
    private const ALLOWED_IDENTITIES = ['buyer', 'seller'];

    public function __construct(
        private readonly AuthService $authService,
        private readonly SmsCodeService $smsCodeService
    ) {
    }

    /**
     * 注册流程（支持自注册与第三方燕尾票据绑定）。
     */
    public function register(array $data): ResultInterface
    {
        $partialToken = trim((string)($data['partial_token'] ?? $data['partialToken'] ?? ''));
        $isThirdParty = $partialToken !== '';
        $partialPayload = [];
        $code = trim((string)($data['code'] ?? ''));
        $inviteCode = trim((string)($data['invite_code'] ?? ''));
        $invitedBy = isset($data['invited_by']) ? (int) $data['invited_by'] : null;
        if ($invitedBy !== null && $invitedBy <= 0) {
            $invitedBy = null;
        }

        if ($isThirdParty) {
            $partialPayload = $this->authService->validatePartialToken($partialToken);
        }

        $phone = trim((string)($data['phone'] ?? ''));
        if ($phone === '') {
            throw new InvalidArgumentException('手机号不能为空');
        }
        if (!preg_match('/^1\d{10}$/', $phone)) {
            throw new InvalidArgumentException('手机号格式不正确');
        }

        if (User::where('phone', $phone)->find()) {
            throw new InvalidArgumentException('手机号已被注册');
        }

        $password = (string)($data['password'] ?? '');
        if ($isThirdParty) {
            if ($code === '') {
                throw new InvalidArgumentException('验证码不能为空');
            }
            if (!$this->smsCodeService->verifyCode(SmsCodeService::SCENE_BIND, $phone, $code)) {
                throw new InvalidArgumentException('验证码已失效或不正确');
            }
            if ($password !== '' && strlen($password) < 6) {
                throw new InvalidArgumentException('密码长度至少 6 位');
            }
        } else {
            if (strlen($password) < 6) {
                throw new InvalidArgumentException('密码长度至少 6 位');
            }
        }
        $passwordHash = $password !== '' ? password_hash($password, PASSWORD_BCRYPT) : null;

        if ($inviteCode !== '') {
            $decodedId = HashUtil::decodeSingle($inviteCode);
            if (!$decodedId) {
                throw new InvalidArgumentException('邀请码无效');
            }
            $invitedBy = $decodedId;
        }

        if ($invitedBy !== null) {
            $inviterExists = User::where('id', $invitedBy)->count() > 0;
            if (!$inviterExists) {
                throw new InvalidArgumentException('邀请人不存在');
            }
        }

        $identities = $this->normalizeIdentities($data['identities'] ?? ($data['identity_type'] ?? 'buyer'));
        $nickname = isset($data['nickname']) ? trim((string)$data['nickname']) : '';
        $realName = isset($data['real_name']) ? trim((string)$data['real_name']) : '';

        $user = Db::transaction(function () use (
            $phone,
            $passwordHash,
            $nickname,
            $realName,
            $identities,
            $data,
            $isThirdParty,
            $partialPayload,
            $invitedBy
        ) {
            $user = User::create([
                'phone' => $phone,
                'password_hash' => $passwordHash,
                'status' => 1,
                'register_channel' => $data['register_channel'] ?? ($isThirdParty ? 'oauth' : 'self'),
                'invited_by' => $invitedBy,
            ]);

            UserProfile::create([
                'user_id' => $user->id,
                'nickname' => $nickname !== '' ? $nickname : mb_substr($phone, -4),
                'real_name' => $realName,
            ]);

            $this->createPhoneAuthRecords($user, $passwordHash);

            if ($isThirdParty) {
                $this->createOauthAuthRecord($user, $partialPayload);
            }

            $this->createIdentities($user, $identities, $data, $isThirdParty, $invitedBy);

            return $user;
        });

        $user = $this->authService->findUserById((int)$user->id);
        $hasActiveIdentity = $this->hasActiveIdentity($user);

        if ($hasActiveIdentity) {
            if ($isThirdParty) {
                $this->smsCodeService->invalidate(SmsCodeService::SCENE_BIND, $phone);
            }
            return $this->authService->buildLoginSuccess($user);
        }

        $result = $this->authService->buildPartialAuthResult(
            [
                'user_id' => $user->id,
                'pending_identity' => $identities,
            ],
            'need_verify_identity',
            '请完善认证资料后再登录',
            [
                'user_id' => $user->id,
                'identities' => $this->authService->getUserIdentitiesData($user),
            ]
        );

        if ($isThirdParty) {
            $this->smsCodeService->invalidate(SmsCodeService::SCENE_BIND, $phone);
        }

        return $result;
    }

    private function createPhoneAuthRecords(User $user, ?string $passwordHash): void
    {
        if ($passwordHash) {
            UserAuth::create([
                'user_id' => $user->id,
                'identity_type' => UserAuth::TYPE_PASSWORD,
                'identifier' => $user->phone,
                'credential' => $passwordHash,
                'status' => 1,
            ]);
        }

        UserAuth::create([
            'user_id' => $user->id,
            'identity_type' => UserAuth::TYPE_SMS,
            'identifier' => $user->phone,
            'credential' => null,
            'status' => 1,
        ]);
    }

    private function createOauthAuthRecord(User $user, array $payload): void
    {
        $identityType = $payload['identity_type'] ?? null;
        $identifier = $payload['identifier'] ?? null;

        if (!$identityType || !$identifier) {
            throw new InvalidArgumentException('部分令牌缺少平台信息');
        }

        UserAuth::create([
            'user_id' => $user->id,
            'identity_type' => $identityType,
            'identifier' => $identifier,
            'credential' => '',
            'unionid' => $payload['unionid'] ?? null,
            'metadata' => $payload['metadata'] ?? null,
            'status' => 1,
        ]);
    }

    private function createIdentities(User $user, array $identities, array $payload, bool $activateBuyer, ?int $invitedBy = null): void
    {
        $now = date('Y-m-d H:i:s');
        $regionId = $payload['region_id'] ?? null;
        $orgId = $payload['org_id'] ?? null;

        foreach ($identities as $identityType) {
            $status = 0;
            if ($identityType === 'buyer' && $activateBuyer) {
                $status = 1;
            }

            UserIdentity::create([
                'user_id' => $user->id,
                'identity_type' => $identityType,
                'region_id' => $regionId,
                'org_id' => $orgId,
                'invited_by' => $invitedBy,
                'status' => $status,
                'verified_at' => $status === 1 ? $now : null,
            ]);
        }
    }

    private function normalizeIdentities($identities): array
    {
        if (!is_array($identities)) {
            $identities = [$identities];
        }

        $identities = array_values(array_unique(array_map(fn($value) => strtolower((string)$value), $identities)));
        if (empty($identities)) {
            $identities = ['buyer'];
        }

        foreach ($identities as $identity) {
            if (!in_array($identity, self::ALLOWED_IDENTITIES, true)) {
                throw new InvalidArgumentException(sprintf('不支持的身份类型：%s', $identity));
            }
        }

        return $identities;
    }

    private function hasActiveIdentity(User $user): bool
    {
        return $user->identities()->where('status', 1)->count() > 0;
    }
}
